﻿// 验证.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include <chrono>

#include"coroutine.h"

using namespace std;

coroutine::Channel<int> channel;   //  类模板的实例化。创建一个类对象。

string async_func()   //  异步函数
{
	std::this_thread::sleep_for(std::chrono::milliseconds(3000));  //  该线程睡眠3000毫秒。
	return "22";   //  返回一个string类对象字符串。
}

void routine_func1()
{
	//  刚开始将运行失败由pop()中的yield()优先运行主线程。
	int i = channel.pop();  //  头文件中的inline是可以省略了的只有在函数定义前显式声明inline会限制它。
	//std::cout << "routine_func1: pop："<< i << std::endl;
	
	i = channel.pop();
	//std::cout << "routine_func1: pop：" << i << std::endl;
}

void routine_func2(int i)
{
	std::cout << "routine_func2: 20" << std::endl;
	coroutine::yield();    //  调用名称空间的函数：暂停当前线程，优先运行其他线程(在函数实现中是切换到主线程)。

	std::cout << "routine_func2: 21" << std::endl;

	//  运行异步线程函数
	//  如果结果未返回(线程超时)，则当前线程给主线程让步。
	string str = coroutine::await(async_func);  //  调用协程名称空间中的API，
	//std::cout << "routine_func2的callback async_func返回值(22): " << str << std::endl;
}

void thread_func()
{
	//  创建Routine结构变量。参数为如std::function<void()>类对象这样的回调函数的函数指针。
	coroutine::routine_t rt1 = coroutine::create(routine_func1);
	coroutine::routine_t rt2 = coroutine::create(std::bind(routine_func2, 2));

	std::cout << "00" << std::endl;
	coroutine::resume(rt1);

	std::cout << "01" << std::endl;
	coroutine::resume(rt2);

	std::cout << "02" << std::endl;
	channel.push(10);   //  前面声明了Type为int类型。

	std::cout << "03" << std::endl;
	coroutine::resume(rt2);

	std::cout << "04" << std::endl;
	channel.push(11);

	std::cout << "05" << std::endl;

	std::this_thread::sleep_for(std::chrono::milliseconds(6000));  //  线程睡眠6000毫秒
	coroutine::resume(rt2);

	//  销毁线程(routine)，释放分配的资源
	//  警告：不要用线程自己销毁线程。
	coroutine::destroy(rt1);
	coroutine::destroy(rt2);
}

int main(void)
{
	using std::cin;
	using std::cout;
	using std::endl;

	std::thread t1(thread_func);
	std::thread t2([]() {
		//  不支持协调线程交叉的例程
		//  该lambda表达式表示匿名函数void()类型的函数指针。
	});
	t1.join();   //  连接
	t2.join();

	/*for (int i = 0; i < str.size(); i++)
	{
		cout << "\"" << str[i] << "\"\n";
	}   */
	
	return 0;
}



// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门提示: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
